if (modifier->xattr_destroy)
modifier->xattr_destroy (modifier->xattr_user_data);
- g_clear_object (&modifier->sepolicy);
g_clear_pointer (&modifier->devino_cache, (GDestroyNotify)g_hash_table_unref);
+ g_clear_object (&modifier->sepolicy);
+ (void) glnx_tmpdir_delete (&modifier->sepolicy_tmpdir, NULL, NULL);
+
g_free (modifier);
return;
}
modifier->sepolicy = sepolicy ? g_object_ref (sepolicy) : NULL;
}
+/**
+ * ostree_repo_commit_modifier_set_sepolicy_from_commit:
+ * @modifier: Commit modifier
+ * @repo: OSTree repo containing @rev
+ * @rev: Find SELinux policy from this base commit
+ * @cancellable:
+ * @error:
+ *
+ * In many cases, one wants to create a "derived" commit from base commit.
+ * SELinux policy labels are part of that base commit. This API allows
+ * one to easily set up SELinux labeling from a base commit.
+ */
+gboolean
+ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier,
+ OstreeRepo *repo,
+ const char *rev,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GLNX_AUTO_PREFIX_ERROR ("setting sepolicy from commit", error);
+ g_autofree char *commit = NULL;
+ g_autoptr(GFile) root = NULL;
+ if (!ostree_repo_read_commit (repo, rev, &root, &commit, cancellable, error))
+ return FALSE;
+ const char policypath[] = "usr/etc/selinux";
+ g_autoptr(GFile) policyroot = g_file_get_child (root, policypath);
+ if (!g_file_query_exists (policyroot, NULL))
+ return TRUE; /* No policy, nothing to do */
+
+ GLnxTmpDir tmpdir = {0,};
+ if (!glnx_mkdtemp ("ostree-commit-sepolicy-XXXXXX", 0700, &tmpdir, error))
+ return FALSE;
+ if (!glnx_shutil_mkdir_p_at (tmpdir.fd, "usr/etc", 0755, cancellable, error))
+ return FALSE;
+
+ OstreeRepoCheckoutAtOptions coopts = {0,};
+ coopts.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+ coopts.subpath = glnx_strjoina ("/", policypath);
+
+ if (!ostree_repo_checkout_at (repo, &coopts, tmpdir.fd, policypath, commit, cancellable, error))
+ return glnx_prefix_error (error, "policy checkout");
+
+ g_autoptr(OstreeSePolicy) policy = ostree_sepolicy_new_at (tmpdir.fd, cancellable, error);
+ if (!policy)
+ return glnx_prefix_error (error, "reading policy");
+
+ ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
+ /* Transfer ownership */
+ modifier->sepolicy_tmpdir = tmpdir;
+ tmpdir.initialized = FALSE;
+
+ return TRUE;
+}
+
/**
* ostree_repo_commit_modifier_set_devino_cache:
* @modifier: Modifier
static char *opt_tar_pathname_filter;
static gboolean opt_no_xattrs;
static char *opt_selinux_policy;
+static gboolean opt_selinux_policy_from_base;
static gboolean opt_canonical_permissions;
static gboolean opt_consume;
static gboolean opt_devino_canonical;
{ "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL },
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL },
{ "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" },
+ { "selinux-policy-from-base", 'P', 0, G_OPTION_ARG_NONE, &opt_selinux_policy_from_base, "Set SELinux labels based on first --tree argument", NULL },
{ "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL },
{ "devino-canonical", 'I', 0, G_OPTION_ARG_NONE, &opt_devino_canonical, "Assume hardlinked objects are unmodified. Implies --link-checkout-speedup", NULL },
{ "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES;
if (opt_disable_fsync)
ostree_repo_set_disable_fsync (repo, TRUE);
+ if (opt_selinux_policy && opt_selinux_policy_from_base)
+ {
+ glnx_throw (error, "Cannot specify both --selinux-policy and --selinux-policy-from-base");
+ goto out;
+ }
if (flags != 0
|| opt_owner_uid >= 0
|| opt_statoverride_file != NULL
|| opt_skiplist_file != NULL
|| opt_no_xattrs
- || opt_selinux_policy)
+ || opt_selinux_policy
+ || opt_selinux_policy_from_base)
{
filter_data.mode_adds = mode_adds;
filter_data.skip_list = skip_list;
modifier = ostree_repo_commit_modifier_new (flags, commit_filter,
&filter_data, NULL);
- if (opt_selinux_policy)
- {
- glnx_autofd int rootfs_dfd = -1;
- if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error))
- {
- g_prefix_error (error, "selinux-policy: ");
- goto out;
- }
- policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
- if (!policy)
- goto out;
- ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
- }
}
if (opt_editor)
g_assert (opt_trees && *opt_trees);
for (tree_iter = (const char *const*)opt_trees; *tree_iter; tree_iter++)
{
+ const gboolean first = (tree_iter == (const char *const*)opt_trees);
tree = *tree_iter;
eq = strchr (tree, '=');
g_clear_object (&object_to_commit);
if (strcmp (tree_type, "dir") == 0)
{
+ if (first && opt_selinux_policy_from_base)
+ {
+ opt_selinux_policy = g_strdup (tree);
+ opt_selinux_policy_from_base = FALSE;
+ }
+ if (first && opt_selinux_policy)
+ {
+ g_assert (modifier);
+ glnx_autofd int rootfs_dfd = -1;
+ if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error))
+ goto out;
+ policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
+ if (!policy)
+ goto out;
+ ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
+ }
if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier,
cancellable, error))
goto out;
}
else if (strcmp (tree_type, "tar") == 0)
{
+ if (first && opt_selinux_policy_from_base)
+ {
+ glnx_throw (error, "Cannot use --selinux-policy-from-base with tar");
+ goto out;
+ }
if (!opt_tar_pathname_filter)
{
if (strcmp (tree, "-") == 0)
}
else if (strcmp (tree_type, "ref") == 0)
{
+ if (first && opt_selinux_policy_from_base)
+ {
+ g_assert (modifier);
+ if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, tree, cancellable, error))
+ goto out;
+ }
if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error))
goto out;